//
//  HMDBManager.m
//  DBDemo(数据库增删改查)
//
//  Created by 陶永久 on 2016/10/25.
//  Copyright © 2016年 taoyongjiu. All rights reserved.
//

#import "HMDBManager.h"
#import <sqlite3.h>

/**
 *  1.创建并打开数据库
 *  2,读取本地的sql文件,导入表
 *  3,执行sql
 *
 *
 **/

@implementation HMDBManager
{
    sqlite3 *_db; //数据库对象
}

#pragma mark -
#pragma mark - 单例
+ (instancetype)sharedDBManager
{
    static id instance;
    
    static dispatch_once_t onceToken;
    
    dispatch_once(&onceToken, ^{
        
        instance = [[self alloc] init];
    });
    
    return instance;
}

#pragma mark -
#pragma mark - 初始化,创建并打开数据库
- (instancetype)init
{
    self = [super init];
    if (self){
        //获取沙盒路径
        NSString *cachePath = [NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES) lastObject];
        
        //拼接文件存放路径
        NSString *filePath = [cachePath stringByAppendingString:@"demo.db"];
        
        NSLog(@"%@",filePath);
        /*
         参数1 : 数据库文件的保存路径
         参数2 : 输出参数, 数据库对象
         */
        int res =  sqlite3_open(filePath.UTF8String, &_db);
        
        if (res == SQLITE_OK)
        {
            NSLog(@"数据库创建成功");
            
            //创建表格,表格的初始化
           if( [self createTables])
           {
               NSLog(@"表创建成功");
           };
        }
         else
         {
             NSLog(@"数据库创建失败");
         }
        
    }
    return self;
}

#pragma mark -
#pragma mark - 创建表,成功返回YES
- (BOOL)createTables
{
    //获取本地的SQL路径
    NSString *filePath = [[NSBundle mainBundle] pathForResource:@"main.sql" ofType:nil];
    
    //根据文件路径读取文件的内容
    NSString *sql = [NSString stringWithContentsOfFile:filePath encoding:NSUTF8StringEncoding error:NULL];
    
    
    return [self execSqlWithSqlString:sql];
}

#pragma mark -
#pragma mark - 传入字符串,执行sql语句,成功返回YES
- (BOOL)execSqlWithSqlString :(NSString *)sql
{
    //执行sql
    //2.执行sql
    //sqlite3*,                                  /* An open database一个已经打开的数据库 */
    //const char *sql,                           /* SQL to be evaluated sql语句 */
    //int (*callback)(void*,int,char**,char**),  /* Callback function 回调*/
    //void *,                                    /* 1st argument to callback 回调里的第一个参数*/
    //char **errmsg                              /* Error msg written here 错误*/
    int res = sqlite3_exec(_db, sql.UTF8String, NULL, NULL, NULL);
    
    if (res == SQLITE_OK)
    {
        return YES;
    }
    return NO;
}

#pragma mark -
#pragma mark - 预编译sql,返回字典的集合(对应数据的key - values)
- (NSArray<NSDictionary *> *)queryRecords:(NSString *)sql
{
    
    NSArray *dictArray;
    /*
     1.数据库的句柄(数据库对象)
     2.要编译的语句
     3.sql的长度 (-1自适应长度)
     4.输出参数 预编译后的对象
     5.指针指向sql中没有使用的部分
     */
    sqlite3_stmt *_stmt;
    if(sqlite3_prepare_v2(_db, sql.UTF8String, -1, &_stmt, NULL) == SQLITE_OK)
    {
        //根据预编译后的sql,获取执行后的结果
        dictArray =  [self getQueryRecordsWithStmt:_stmt];
        
    }else
    {
        NSLog(@"预编译失败");
    };
    
    return dictArray;
}

#pragma mark -
#pragma mark - 执行预编译的sql,返回执行后的结果
- (NSArray *)getQueryRecordsWithStmt :(sqlite3_stmt *)stmt
{
    //可变数组,存储字典
    NSMutableArray *arrayM = [NSMutableArray array];
    
    //获取下一行的数据,返回下一行是否有数据
    while (sqlite3_step(stmt) == SQLITE_ROW)  //有数据,进入循环
    {
        //字典,存储每列的名字与对应的value
        NSMutableDictionary *dic = [NSMutableDictionary dictionary];
        
        //获取每一行有多少列
        int colCount = sqlite3_column_count(stmt);
        
        //循环获取每列的名字
        for (int i = 0; i < colCount; i++)
        {
            //获取每列的名字
            const char* colName = sqlite3_column_name(stmt, i);
            
            //转换为NSString,作为字典的key
            NSString *keyStr = [NSString stringWithUTF8String:colName];
            
            //获取数据类型
            int colDataType = sqlite3_column_type(stmt, i);
            
            switch (colDataType)
            {
                case SQLITE_INTEGER:
                {
                    int value = sqlite3_column_int(stmt, i);
                    [dic setObject:@(value) forKey:keyStr];
                }
                    break;
                case SQLITE_TEXT:
                {
                    const char *value = (const char *)sqlite3_column_text(stmt, i);
                    
                    [dic setObject:[NSString stringWithUTF8String:value] forKey:keyStr];
                    
                }
                    break;
            }
        }
        [arrayM addObject:dic];
    }
    return arrayM.copy;
}

@end
